From 73533671cdb8c701d6866f73b943c5b58a7009d9 Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Tue, 30 Aug 2005 12:41:54 -0600 Subject: [PATCH] Enable CONFIG_SMP compile and link --- xen/arch/ia64/hyperprivop.S | 8 +- xen/arch/ia64/irq.c | 9 +- xen/arch/ia64/linux-xen/irq_ia64.c | 2 + xen/arch/ia64/linux-xen/mm_contig.c | 7 +- xen/arch/ia64/{linux => linux-xen}/sal.c | 3 + xen/arch/ia64/linux-xen/smp.c | 427 +++++++++ xen/arch/ia64/linux-xen/smpboot.c | 903 ++++++++++++++++++ xen/arch/ia64/process.c | 2 +- xen/arch/ia64/smp.c | 43 - xen/arch/ia64/smpboot.c | 2 - xen/arch/ia64/xensetup.c | 2 + xen/arch/ia64/xentime.c | 4 + xen/include/asm-ia64/config.h | 38 +- xen/include/asm-ia64/linux-xen/asm/pal.h | 70 ++ .../asm-ia64/linux-xen/asm/processor.h | 7 + .../{linux => linux-xen}/asm/spinlock.h | 33 + xen/include/asm-ia64/linux-xen/asm/system.h | 6 +- xen/include/asm-ia64/linux-xen/asm/tlbflush.h | 105 ++ xen/include/asm-ia64/linux/asm/sal.h | 50 + xen/include/asm-ia64/linux/asm/tlbflush.h | 0 xen/include/asm-ia64/linux/notifier.h | 76 ++ xen/include/asm-ia64/vhpt.h | 2 +- 22 files changed, 1735 insertions(+), 64 deletions(-) rename xen/arch/ia64/{linux => linux-xen}/sal.c (99%) create mode 100644 xen/arch/ia64/linux-xen/smp.c create mode 100644 xen/arch/ia64/linux-xen/smpboot.c delete mode 100644 xen/arch/ia64/smp.c delete mode 100644 xen/arch/ia64/smpboot.c rename xen/include/asm-ia64/{linux => linux-xen}/asm/spinlock.h (83%) create mode 100644 xen/include/asm-ia64/linux-xen/asm/tlbflush.h delete mode 100644 xen/include/asm-ia64/linux/asm/tlbflush.h create mode 100644 xen/include/asm-ia64/linux/notifier.h diff --git a/xen/arch/ia64/hyperprivop.S b/xen/arch/ia64/hyperprivop.S index d142318894..d823dde6e1 100644 --- a/xen/arch/ia64/hyperprivop.S +++ b/xen/arch/ia64/hyperprivop.S @@ -27,6 +27,11 @@ #undef RFI_TO_INTERRUPT // not working yet #endif +#ifdef CONFIG_SMP +#warning "FIXME: ptc.ga instruction requires spinlock for SMP" +#undef FAST_PTC_GA +#endif + // FIXME: turn off for now... but NaTs may crash Xen so re-enable soon! //#define HANDLE_AR_UNAT @@ -1506,9 +1511,6 @@ GLOBAL_ENTRY(hyper_thash) END(hyper_thash) ENTRY(hyper_ptc_ga) -#ifdef CONFIG_SMP -FIXME: ptc.ga instruction requires spinlock for SMP -#endif #ifndef FAST_PTC_GA br.spnt.few dispatch_break_fault ;; #endif diff --git a/xen/arch/ia64/irq.c b/xen/arch/ia64/irq.c index 473e0afdae..b694d62bc9 100644 --- a/xen/arch/ia64/irq.c +++ b/xen/arch/ia64/irq.c @@ -266,8 +266,12 @@ skip: #ifdef CONFIG_SMP inline void synchronize_irq(unsigned int irq) { - while (irq_descp(irq)->status & IRQ_INPROGRESS) +#ifndef XEN + struct irq_desc *desc = irq_desc + irq; + + while (desc->status & IRQ_INPROGRESS) cpu_relax(); +#endif } EXPORT_SYMBOL(synchronize_irq); #endif @@ -1012,6 +1016,8 @@ int setup_irq(unsigned int irq, struct irqaction * new) return 0; } +#ifndef XEN + static struct proc_dir_entry * root_irq_dir; static struct proc_dir_entry * irq_dir [NR_IRQS]; @@ -1121,6 +1127,7 @@ void move_irq(int irq) #endif /* CONFIG_SMP */ +#endif #ifdef CONFIG_HOTPLUG_CPU unsigned int vectors_in_migration[NR_IRQS]; diff --git a/xen/arch/ia64/linux-xen/irq_ia64.c b/xen/arch/ia64/linux-xen/irq_ia64.c index a3762df227..a0272bcc82 100644 --- a/xen/arch/ia64/linux-xen/irq_ia64.c +++ b/xen/arch/ia64/linux-xen/irq_ia64.c @@ -323,7 +323,9 @@ extern irqreturn_t handle_IPI (int irq, void *dev_id, struct pt_regs *regs); static struct irqaction ipi_irqaction = { .handler = handle_IPI, +#ifndef XEN .flags = SA_INTERRUPT, +#endif .name = "IPI" }; #endif diff --git a/xen/arch/ia64/linux-xen/mm_contig.c b/xen/arch/ia64/linux-xen/mm_contig.c index 1930a3f27c..87ab66deca 100644 --- a/xen/arch/ia64/linux-xen/mm_contig.c +++ b/xen/arch/ia64/linux-xen/mm_contig.c @@ -191,8 +191,13 @@ per_cpu_init (void) * get_zeroed_page(). */ if (smp_processor_id() == 0) { +#ifdef XEN + cpu_data = alloc_xenheap_pages(PERCPU_PAGE_SIZE - + PAGE_SIZE + get_order(NR_CPUS)); +#else cpu_data = __alloc_bootmem(PERCPU_PAGE_SIZE * NR_CPUS, PERCPU_PAGE_SIZE, __pa(MAX_DMA_ADDRESS)); +#endif for (cpu = 0; cpu < NR_CPUS; cpu++) { memcpy(cpu_data, __phys_per_cpu_start, __per_cpu_end - __per_cpu_start); __per_cpu_offset[cpu] = (char *) cpu_data - __per_cpu_start; @@ -204,6 +209,7 @@ per_cpu_init (void) } #endif /* CONFIG_SMP */ +#ifndef XEN static int count_pages (u64 start, u64 end, void *arg) { @@ -229,7 +235,6 @@ count_dma_pages (u64 start, u64 end, void *arg) * Set up the page tables. */ -#ifndef XEN void paging_init (void) { diff --git a/xen/arch/ia64/linux/sal.c b/xen/arch/ia64/linux-xen/sal.c similarity index 99% rename from xen/arch/ia64/linux/sal.c rename to xen/arch/ia64/linux-xen/sal.c index acc0f132f8..2271820246 100644 --- a/xen/arch/ia64/linux/sal.c +++ b/xen/arch/ia64/linux-xen/sal.c @@ -17,6 +17,9 @@ #include #include #include +#ifdef XEN +#include +#endif __cacheline_aligned DEFINE_SPINLOCK(sal_lock); unsigned long sal_platform_features; diff --git a/xen/arch/ia64/linux-xen/smp.c b/xen/arch/ia64/linux-xen/smp.c new file mode 100644 index 0000000000..872ea4b025 --- /dev/null +++ b/xen/arch/ia64/linux-xen/smp.c @@ -0,0 +1,427 @@ +/* + * SMP Support + * + * Copyright (C) 1999 Walt Drummond + * Copyright (C) 1999, 2001, 2003 David Mosberger-Tang + * + * Lots of stuff stolen from arch/alpha/kernel/smp.c + * + * 01/05/16 Rohit Seth IA64-SMP functions. Reorganized + * the existing code (on the lines of x86 port). + * 00/09/11 David Mosberger Do loops_per_jiffy + * calibration on each CPU. + * 00/08/23 Asit Mallick fixed logical processor id + * 00/03/31 Rohit Seth Fixes for Bootstrap Processor + * & cpu_online_map now gets done here (instead of setup.c) + * 99/10/05 davidm Update to bring it in sync with new command-line processing + * scheme. + * 10/13/00 Goutham Rao Updated smp_call_function and + * smp_call_function_single to resend IPI on timeouts + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef XEN +#include +#endif + +#ifdef XEN +// FIXME: MOVE ELSEWHERE +//Huh? This seems to be used on ia64 even if !CONFIG_SMP +void flush_tlb_mask(cpumask_t mask) +{ + dummy(); +} +//#if CONFIG_SMP || IA64 +#if CONFIG_SMP +//Huh? This seems to be used on ia64 even if !CONFIG_SMP +void smp_send_event_check_mask(cpumask_t mask) +{ + dummy(); + //send_IPI_mask(cpu_mask, EVENT_CHECK_VECTOR); +} + + +//Huh? This seems to be used on ia64 even if !CONFIG_SMP +int try_flush_tlb_mask(cpumask_t mask) +{ + dummy(); + return 1; +} +#endif +#endif + +#ifdef CONFIG_SMP /* ifdef XEN */ + +/* + * Structure and data for smp_call_function(). This is designed to minimise static memory + * requirements. It also looks cleaner. + */ +static __cacheline_aligned DEFINE_SPINLOCK(call_lock); + +struct call_data_struct { + void (*func) (void *info); + void *info; + long wait; + atomic_t started; + atomic_t finished; +}; + +static volatile struct call_data_struct *call_data; + +#define IPI_CALL_FUNC 0 +#define IPI_CPU_STOP 1 + +/* This needs to be cacheline aligned because it is written to by *other* CPUs. */ +static DEFINE_PER_CPU(u64, ipi_operation) ____cacheline_aligned; + +extern void cpu_halt (void); + +void +lock_ipi_calllock(void) +{ + spin_lock_irq(&call_lock); +} + +void +unlock_ipi_calllock(void) +{ + spin_unlock_irq(&call_lock); +} + +static void +stop_this_cpu (void) +{ + /* + * Remove this CPU: + */ + cpu_clear(smp_processor_id(), cpu_online_map); + max_xtp(); + local_irq_disable(); +#ifndef XEN + cpu_halt(); +#endif +} + +void +cpu_die(void) +{ + max_xtp(); + local_irq_disable(); +#ifndef XEN + cpu_halt(); +#endif + /* Should never be here */ + BUG(); + for (;;); +} + +irqreturn_t +handle_IPI (int irq, void *dev_id, struct pt_regs *regs) +{ + int this_cpu = get_cpu(); + unsigned long *pending_ipis = &__ia64_per_cpu_var(ipi_operation); + unsigned long ops; + + mb(); /* Order interrupt and bit testing. */ + while ((ops = xchg(pending_ipis, 0)) != 0) { + mb(); /* Order bit clearing and data access. */ + do { + unsigned long which; + + which = ffz(~ops); + ops &= ~(1 << which); + + switch (which) { + case IPI_CALL_FUNC: + { + struct call_data_struct *data; + void (*func)(void *info); + void *info; + int wait; + + /* release the 'pointer lock' */ + data = (struct call_data_struct *) call_data; + func = data->func; + info = data->info; + wait = data->wait; + + mb(); + atomic_inc(&data->started); + /* + * At this point the structure may be gone unless + * wait is true. + */ + (*func)(info); + + /* Notify the sending CPU that the task is done. */ + mb(); + if (wait) + atomic_inc(&data->finished); + } + break; + + case IPI_CPU_STOP: + stop_this_cpu(); + break; + + default: + printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which); + break; + } + } while (ops); + mb(); /* Order data access and bit testing. */ + } + put_cpu(); + return IRQ_HANDLED; +} + +/* + * Called with preeemption disabled. + */ +static inline void +send_IPI_single (int dest_cpu, int op) +{ + set_bit(op, &per_cpu(ipi_operation, dest_cpu)); + platform_send_ipi(dest_cpu, IA64_IPI_VECTOR, IA64_IPI_DM_INT, 0); +} + +/* + * Called with preeemption disabled. + */ +static inline void +send_IPI_allbutself (int op) +{ + unsigned int i; + + for (i = 0; i < NR_CPUS; i++) { + if (cpu_online(i) && i != smp_processor_id()) + send_IPI_single(i, op); + } +} + +/* + * Called with preeemption disabled. + */ +static inline void +send_IPI_all (int op) +{ + int i; + + for (i = 0; i < NR_CPUS; i++) + if (cpu_online(i)) + send_IPI_single(i, op); +} + +/* + * Called with preeemption disabled. + */ +static inline void +send_IPI_self (int op) +{ + send_IPI_single(smp_processor_id(), op); +} + +/* + * Called with preeemption disabled. + */ +void +smp_send_reschedule (int cpu) +{ + platform_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0); +} + +void +smp_flush_tlb_all (void) +{ + on_each_cpu((void (*)(void *))local_flush_tlb_all, NULL, 1, 1); +} + +void +smp_flush_tlb_mm (struct mm_struct *mm) +{ + preempt_disable(); + /* this happens for the common case of a single-threaded fork(): */ + if (likely(mm == current->active_mm && atomic_read(&mm->mm_users) == 1)) + { + local_finish_flush_tlb_mm(mm); + preempt_enable(); + return; + } + + preempt_enable(); + /* + * We could optimize this further by using mm->cpu_vm_mask to track which CPUs + * have been running in the address space. It's not clear that this is worth the + * trouble though: to avoid races, we have to raise the IPI on the target CPU + * anyhow, and once a CPU is interrupted, the cost of local_flush_tlb_all() is + * rather trivial. + */ + on_each_cpu((void (*)(void *))local_finish_flush_tlb_mm, mm, 1, 1); +} + +/* + * Run a function on another CPU + * The function to run. This must be fast and non-blocking. + * An arbitrary pointer to pass to the function. + * Currently unused. + * If true, wait until function has completed on other CPUs. + * [RETURNS] 0 on success, else a negative status code. + * + * Does not return until the remote CPU is nearly ready to execute + * or is or has executed. + */ + +int +smp_call_function_single (int cpuid, void (*func) (void *info), void *info, int nonatomic, + int wait) +{ + struct call_data_struct data; + int cpus = 1; + int me = get_cpu(); /* prevent preemption and reschedule on another processor */ + + if (cpuid == me) { + printk(KERN_INFO "%s: trying to call self\n", __FUNCTION__); + put_cpu(); + return -EBUSY; + } + + data.func = func; + data.info = info; + atomic_set(&data.started, 0); + data.wait = wait; + if (wait) + atomic_set(&data.finished, 0); + +#ifdef XEN + spin_lock(&call_lock); +#else + spin_lock_bh(&call_lock); +#endif + + call_data = &data; + mb(); /* ensure store to call_data precedes setting of IPI_CALL_FUNC */ + send_IPI_single(cpuid, IPI_CALL_FUNC); + + /* Wait for response */ + while (atomic_read(&data.started) != cpus) + cpu_relax(); + + if (wait) + while (atomic_read(&data.finished) != cpus) + cpu_relax(); + call_data = NULL; + +#ifdef XEN + spin_unlock(&call_lock); +#else + spin_unlock_bh(&call_lock); +#endif + put_cpu(); + return 0; +} +EXPORT_SYMBOL(smp_call_function_single); + +/* + * this function sends a 'generic call function' IPI to all other CPUs + * in the system. + */ + +/* + * [SUMMARY] Run a function on all other CPUs. + * The function to run. This must be fast and non-blocking. + * An arbitrary pointer to pass to the function. + * currently unused. + * If true, wait (atomically) until function has completed on other CPUs. + * [RETURNS] 0 on success, else a negative status code. + * + * Does not return until remote CPUs are nearly ready to execute or are or have + * executed. + * + * You must not call this function with disabled interrupts or from a + * hardware interrupt handler or from a bottom half handler. + */ +int +smp_call_function (void (*func) (void *info), void *info, int nonatomic, int wait) +{ + struct call_data_struct data; + int cpus = num_online_cpus()-1; + + if (!cpus) + return 0; + + /* Can deadlock when called with interrupts disabled */ +#ifdef XEN + if (irqs_disabled()) panic("smp_call_function called with interrupts disabled\n"); +#else + WARN_ON(irqs_disabled()); +#endif + + data.func = func; + data.info = info; + atomic_set(&data.started, 0); + data.wait = wait; + if (wait) + atomic_set(&data.finished, 0); + + spin_lock(&call_lock); + + call_data = &data; + mb(); /* ensure store to call_data precedes setting of IPI_CALL_FUNC */ + send_IPI_allbutself(IPI_CALL_FUNC); + + /* Wait for response */ + while (atomic_read(&data.started) != cpus) + cpu_relax(); + + if (wait) + while (atomic_read(&data.finished) != cpus) + cpu_relax(); + call_data = NULL; + + spin_unlock(&call_lock); + return 0; +} +EXPORT_SYMBOL(smp_call_function); + +/* + * this function calls the 'stop' function on all other CPUs in the system. + */ +void +smp_send_stop (void) +{ + send_IPI_allbutself(IPI_CPU_STOP); +} + +int __init +setup_profiling_timer (unsigned int multiplier) +{ + return -EINVAL; +} +#endif /* CONFIG_SMP ifdef XEN */ diff --git a/xen/arch/ia64/linux-xen/smpboot.c b/xen/arch/ia64/linux-xen/smpboot.c new file mode 100644 index 0000000000..92c9dec161 --- /dev/null +++ b/xen/arch/ia64/linux-xen/smpboot.c @@ -0,0 +1,903 @@ +/* + * SMP boot-related support + * + * Copyright (C) 1998-2003, 2005 Hewlett-Packard Co + * David Mosberger-Tang + * Copyright (C) 2001, 2004-2005 Intel Corp + * Rohit Seth + * Suresh Siddha + * Gordon Jin + * Ashok Raj + * + * 01/05/16 Rohit Seth Moved SMP booting functions from smp.c to here. + * 01/04/27 David Mosberger Added ITC synching code. + * 02/07/31 David Mosberger Switch over to hotplug-CPU boot-sequence. + * smp_boot_cpus()/smp_commence() is replaced by + * smp_prepare_cpus()/__cpu_up()/smp_cpus_done(). + * 04/06/21 Ashok Raj Added CPU Hotplug Support + * 04/12/26 Jin Gordon + * 04/12/26 Rohit Seth + * Add multi-threading and multi-core detection + * 05/01/30 Suresh Siddha + * Setup cpu_sibling_map and cpu_core_map + */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* hg add me */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef XEN +#include +int ht_per_core = 1; +#endif + +#ifdef CONFIG_SMP /* ifdef XEN */ + +#define SMP_DEBUG 0 + +#if SMP_DEBUG +#define Dprintk(x...) printk(x) +#else +#define Dprintk(x...) +#endif + +#ifdef CONFIG_HOTPLUG_CPU +/* + * Store all idle threads, this can be reused instead of creating + * a new thread. Also avoids complicated thread destroy functionality + * for idle threads. + */ +struct task_struct *idle_thread_array[NR_CPUS]; + +/* + * Global array allocated for NR_CPUS at boot time + */ +struct sal_to_os_boot sal_boot_rendez_state[NR_CPUS]; + +/* + * start_ap in head.S uses this to store current booting cpu + * info. + */ +struct sal_to_os_boot *sal_state_for_booting_cpu = &sal_boot_rendez_state[0]; + +#define set_brendez_area(x) (sal_state_for_booting_cpu = &sal_boot_rendez_state[(x)]); + +#define get_idle_for_cpu(x) (idle_thread_array[(x)]) +#define set_idle_for_cpu(x,p) (idle_thread_array[(x)] = (p)) + +#else + +#define get_idle_for_cpu(x) (NULL) +#define set_idle_for_cpu(x,p) +#define set_brendez_area(x) +#endif + + +/* + * ITC synchronization related stuff: + */ +#define MASTER 0 +#define SLAVE (SMP_CACHE_BYTES/8) + +#define NUM_ROUNDS 64 /* magic value */ +#define NUM_ITERS 5 /* likewise */ + +static DEFINE_SPINLOCK(itc_sync_lock); +static volatile unsigned long go[SLAVE + 1]; + +#define DEBUG_ITC_SYNC 0 + +extern void __devinit calibrate_delay (void); +extern void start_ap (void); +extern unsigned long ia64_iobase; + +task_t *task_for_booting_cpu; + +/* + * State for each CPU + */ +DEFINE_PER_CPU(int, cpu_state); + +/* Bitmasks of currently online, and possible CPUs */ +cpumask_t cpu_online_map; +EXPORT_SYMBOL(cpu_online_map); +cpumask_t cpu_possible_map; +EXPORT_SYMBOL(cpu_possible_map); + +cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned; +cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned; +int smp_num_siblings = 1; +int smp_num_cpucores = 1; + +/* which logical CPU number maps to which CPU (physical APIC ID) */ +volatile int ia64_cpu_to_sapicid[NR_CPUS]; +EXPORT_SYMBOL(ia64_cpu_to_sapicid); + +static volatile cpumask_t cpu_callin_map; + +struct smp_boot_data smp_boot_data __initdata; + +unsigned long ap_wakeup_vector = -1; /* External Int use to wakeup APs */ + +char __initdata no_int_routing; + +unsigned char smp_int_redirect; /* are INT and IPI redirectable by the chipset? */ + +static int __init +nointroute (char *str) +{ + no_int_routing = 1; + printk ("no_int_routing on\n"); + return 1; +} + +__setup("nointroute", nointroute); + +void +sync_master (void *arg) +{ + unsigned long flags, i; + + go[MASTER] = 0; + + local_irq_save(flags); + { + for (i = 0; i < NUM_ROUNDS*NUM_ITERS; ++i) { + while (!go[MASTER]) + cpu_relax(); + go[MASTER] = 0; + go[SLAVE] = ia64_get_itc(); + } + } + local_irq_restore(flags); +} + +/* + * Return the number of cycles by which our itc differs from the itc on the master + * (time-keeper) CPU. A positive number indicates our itc is ahead of the master, + * negative that it is behind. + */ +static inline long +get_delta (long *rt, long *master) +{ + unsigned long best_t0 = 0, best_t1 = ~0UL, best_tm = 0; + unsigned long tcenter, t0, t1, tm; + long i; + + for (i = 0; i < NUM_ITERS; ++i) { + t0 = ia64_get_itc(); + go[MASTER] = 1; + while (!(tm = go[SLAVE])) + cpu_relax(); + go[SLAVE] = 0; + t1 = ia64_get_itc(); + + if (t1 - t0 < best_t1 - best_t0) + best_t0 = t0, best_t1 = t1, best_tm = tm; + } + + *rt = best_t1 - best_t0; + *master = best_tm - best_t0; + + /* average best_t0 and best_t1 without overflow: */ + tcenter = (best_t0/2 + best_t1/2); + if (best_t0 % 2 + best_t1 % 2 == 2) + ++tcenter; + return tcenter - best_tm; +} + +/* + * Synchronize ar.itc of the current (slave) CPU with the ar.itc of the MASTER CPU + * (normally the time-keeper CPU). We use a closed loop to eliminate the possibility of + * unaccounted-for errors (such as getting a machine check in the middle of a calibration + * step). The basic idea is for the slave to ask the master what itc value it has and to + * read its own itc before and after the master responds. Each iteration gives us three + * timestamps: + * + * slave master + * + * t0 ---\ + * ---\ + * ---> + * tm + * /--- + * /--- + * t1 <--- + * + * + * The goal is to adjust the slave's ar.itc such that tm falls exactly half-way between t0 + * and t1. If we achieve this, the clocks are synchronized provided the interconnect + * between the slave and the master is symmetric. Even if the interconnect were + * asymmetric, we would still know that the synchronization error is smaller than the + * roundtrip latency (t0 - t1). + * + * When the interconnect is quiet and symmetric, this lets us synchronize the itc to + * within one or two cycles. However, we can only *guarantee* that the synchronization is + * accurate to within a round-trip time, which is typically in the range of several + * hundred cycles (e.g., ~500 cycles). In practice, this means that the itc's are usually + * almost perfectly synchronized, but we shouldn't assume that the accuracy is much better + * than half a micro second or so. + */ +void +ia64_sync_itc (unsigned int master) +{ + long i, delta, adj, adjust_latency = 0, done = 0; + unsigned long flags, rt, master_time_stamp, bound; +#if DEBUG_ITC_SYNC + struct { + long rt; /* roundtrip time */ + long master; /* master's timestamp */ + long diff; /* difference between midpoint and master's timestamp */ + long lat; /* estimate of itc adjustment latency */ + } t[NUM_ROUNDS]; +#endif + + /* + * Make sure local timer ticks are disabled while we sync. If + * they were enabled, we'd have to worry about nasty issues + * like setting the ITC ahead of (or a long time before) the + * next scheduled tick. + */ + BUG_ON((ia64_get_itv() & (1 << 16)) == 0); + + go[MASTER] = 1; + + if (smp_call_function_single(master, sync_master, NULL, 1, 0) < 0) { + printk(KERN_ERR "sync_itc: failed to get attention of CPU %u!\n", master); + return; + } + + while (go[MASTER]) + cpu_relax(); /* wait for master to be ready */ + + spin_lock_irqsave(&itc_sync_lock, flags); + { + for (i = 0; i < NUM_ROUNDS; ++i) { + delta = get_delta(&rt, &master_time_stamp); + if (delta == 0) { + done = 1; /* let's lock on to this... */ + bound = rt; + } + + if (!done) { + if (i > 0) { + adjust_latency += -delta; + adj = -delta + adjust_latency/4; + } else + adj = -delta; + + ia64_set_itc(ia64_get_itc() + adj); + } +#if DEBUG_ITC_SYNC + t[i].rt = rt; + t[i].master = master_time_stamp; + t[i].diff = delta; + t[i].lat = adjust_latency/4; +#endif + } + } + spin_unlock_irqrestore(&itc_sync_lock, flags); + +#if DEBUG_ITC_SYNC + for (i = 0; i < NUM_ROUNDS; ++i) + printk("rt=%5ld master=%5ld diff=%5ld adjlat=%5ld\n", + t[i].rt, t[i].master, t[i].diff, t[i].lat); +#endif + + printk(KERN_INFO "CPU %d: synchronized ITC with CPU %u (last diff %ld cycles, " + "maxerr %lu cycles)\n", smp_processor_id(), master, delta, rt); +} + +/* + * Ideally sets up per-cpu profiling hooks. Doesn't do much now... + */ +static inline void __devinit +smp_setup_percpu_timer (void) +{ +} + +static void __devinit +smp_callin (void) +{ + int cpuid, phys_id; + extern void ia64_init_itm(void); + +#ifdef CONFIG_PERFMON + extern void pfm_init_percpu(void); +#endif + + cpuid = smp_processor_id(); + phys_id = hard_smp_processor_id(); + + if (cpu_online(cpuid)) { + printk(KERN_ERR "huh, phys CPU#0x%x, CPU#0x%x already present??\n", + phys_id, cpuid); + BUG(); + } + + lock_ipi_calllock(); + cpu_set(cpuid, cpu_online_map); + unlock_ipi_calllock(); + per_cpu(cpu_state, cpuid) = CPU_ONLINE; + + smp_setup_percpu_timer(); + +#ifndef XEN + ia64_mca_cmc_vector_setup(); /* Setup vector on AP */ +#endif + +#ifdef CONFIG_PERFMON + pfm_init_percpu(); +#endif + + local_irq_enable(); + + if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) { + /* + * Synchronize the ITC with the BP. Need to do this after irqs are + * enabled because ia64_sync_itc() calls smp_call_function_single(), which + * calls spin_unlock_bh(), which calls spin_unlock_bh(), which calls + * local_bh_enable(), which bugs out if irqs are not enabled... + */ + Dprintk("Going to syncup ITC with BP.\n"); + ia64_sync_itc(0); + } + + /* + * Get our bogomips. + */ + ia64_init_itm(); +#ifndef XEN + calibrate_delay(); +#endif + local_cpu_data->loops_per_jiffy = loops_per_jiffy; + +#ifdef CONFIG_IA32_SUPPORT + ia32_gdt_init(); +#endif + + /* + * Allow the master to continue. + */ + cpu_set(cpuid, cpu_callin_map); + Dprintk("Stack on CPU %d at about %p\n",cpuid, &cpuid); +} + + +/* + * Activate a secondary processor. head.S calls this. + */ +int __devinit +start_secondary (void *unused) +{ + /* Early console may use I/O ports */ + ia64_set_kr(IA64_KR_IO_BASE, __pa(ia64_iobase)); + Dprintk("start_secondary: starting CPU 0x%x\n", hard_smp_processor_id()); + efi_map_pal_code(); + cpu_init(); + smp_callin(); + +#ifdef XEN + startup_cpu_idle_loop(); +#else + cpu_idle(); +#endif + return 0; +} + +struct pt_regs * __devinit idle_regs(struct pt_regs *regs) +{ + return NULL; +} + +#ifndef XEN +struct create_idle { + struct task_struct *idle; + struct completion done; + int cpu; +}; + +void +do_fork_idle(void *_c_idle) +{ + struct create_idle *c_idle = _c_idle; + + c_idle->idle = fork_idle(c_idle->cpu); + complete(&c_idle->done); +} +#endif + +static int __devinit +do_boot_cpu (int sapicid, int cpu) +{ + int timeout; +#ifndef XEN + struct create_idle c_idle = { + .cpu = cpu, + .done = COMPLETION_INITIALIZER(c_idle.done), + }; + DECLARE_WORK(work, do_fork_idle, &c_idle); + + c_idle.idle = get_idle_for_cpu(cpu); + if (c_idle.idle) { + init_idle(c_idle.idle, cpu); + goto do_rest; + } + + /* + * We can't use kernel_thread since we must avoid to reschedule the child. + */ + if (!keventd_up() || current_is_keventd()) + work.func(work.data); + else { + schedule_work(&work); + wait_for_completion(&c_idle.done); + } + + if (IS_ERR(c_idle.idle)) + panic("failed fork for CPU %d", cpu); + + set_idle_for_cpu(cpu, c_idle.idle); + +do_rest: + task_for_booting_cpu = c_idle.idle; +#endif + + Dprintk("Sending wakeup vector %lu to AP 0x%x/0x%x.\n", ap_wakeup_vector, cpu, sapicid); + + set_brendez_area(cpu); + platform_send_ipi(cpu, ap_wakeup_vector, IA64_IPI_DM_INT, 0); + + /* + * Wait 10s total for the AP to start + */ + Dprintk("Waiting on callin_map ..."); + for (timeout = 0; timeout < 100000; timeout++) { + if (cpu_isset(cpu, cpu_callin_map)) + break; /* It has booted */ + udelay(100); + } + Dprintk("\n"); + + if (!cpu_isset(cpu, cpu_callin_map)) { + printk(KERN_ERR "Processor 0x%x/0x%x is stuck.\n", cpu, sapicid); + ia64_cpu_to_sapicid[cpu] = -1; + cpu_clear(cpu, cpu_online_map); /* was set in smp_callin() */ + return -EINVAL; + } + return 0; +} + +static int __init +decay (char *str) +{ + int ticks; + get_option (&str, &ticks); + return 1; +} + +__setup("decay=", decay); + +/* + * Initialize the logical CPU number to SAPICID mapping + */ +void __init +smp_build_cpu_map (void) +{ + int sapicid, cpu, i; + int boot_cpu_id = hard_smp_processor_id(); + + for (cpu = 0; cpu < NR_CPUS; cpu++) { + ia64_cpu_to_sapicid[cpu] = -1; +#ifdef CONFIG_HOTPLUG_CPU + cpu_set(cpu, cpu_possible_map); +#endif + } + + ia64_cpu_to_sapicid[0] = boot_cpu_id; + cpus_clear(cpu_present_map); + cpu_set(0, cpu_present_map); + cpu_set(0, cpu_possible_map); + for (cpu = 1, i = 0; i < smp_boot_data.cpu_count; i++) { + sapicid = smp_boot_data.cpu_phys_id[i]; + if (sapicid == boot_cpu_id) + continue; + cpu_set(cpu, cpu_present_map); + cpu_set(cpu, cpu_possible_map); + ia64_cpu_to_sapicid[cpu] = sapicid; + cpu++; + } +} + +/* + * Cycle through the APs sending Wakeup IPIs to boot each. + */ +void __init +smp_prepare_cpus (unsigned int max_cpus) +{ + int boot_cpu_id = hard_smp_processor_id(); + + /* + * Initialize the per-CPU profiling counter/multiplier + */ + + smp_setup_percpu_timer(); + + /* + * We have the boot CPU online for sure. + */ + cpu_set(0, cpu_online_map); + cpu_set(0, cpu_callin_map); + + local_cpu_data->loops_per_jiffy = loops_per_jiffy; + ia64_cpu_to_sapicid[0] = boot_cpu_id; + + printk(KERN_INFO "Boot processor id 0x%x/0x%x\n", 0, boot_cpu_id); + + current_thread_info()->cpu = 0; + + /* + * If SMP should be disabled, then really disable it! + */ + if (!max_cpus) { + printk(KERN_INFO "SMP mode deactivated.\n"); + cpus_clear(cpu_online_map); + cpus_clear(cpu_present_map); + cpus_clear(cpu_possible_map); + cpu_set(0, cpu_online_map); + cpu_set(0, cpu_present_map); + cpu_set(0, cpu_possible_map); + return; + } +} + +void __devinit smp_prepare_boot_cpu(void) +{ + cpu_set(smp_processor_id(), cpu_online_map); + cpu_set(smp_processor_id(), cpu_callin_map); + per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE; +} + +/* + * mt_info[] is a temporary store for all info returned by + * PAL_LOGICAL_TO_PHYSICAL, to be copied into cpuinfo_ia64 when the + * specific cpu comes. + */ +static struct { + __u32 socket_id; + __u16 core_id; + __u16 thread_id; + __u16 proc_fixed_addr; + __u8 valid; +} mt_info[NR_CPUS] __devinitdata; + +#ifdef CONFIG_HOTPLUG_CPU +static inline void +remove_from_mtinfo(int cpu) +{ + int i; + + for_each_cpu(i) + if (mt_info[i].valid && mt_info[i].socket_id == + cpu_data(cpu)->socket_id) + mt_info[i].valid = 0; +} + +static inline void +clear_cpu_sibling_map(int cpu) +{ + int i; + + for_each_cpu_mask(i, cpu_sibling_map[cpu]) + cpu_clear(cpu, cpu_sibling_map[i]); + for_each_cpu_mask(i, cpu_core_map[cpu]) + cpu_clear(cpu, cpu_core_map[i]); + + cpu_sibling_map[cpu] = cpu_core_map[cpu] = CPU_MASK_NONE; +} + +static void +remove_siblinginfo(int cpu) +{ + int last = 0; + + if (cpu_data(cpu)->threads_per_core == 1 && + cpu_data(cpu)->cores_per_socket == 1) { + cpu_clear(cpu, cpu_core_map[cpu]); + cpu_clear(cpu, cpu_sibling_map[cpu]); + return; + } + + last = (cpus_weight(cpu_core_map[cpu]) == 1 ? 1 : 0); + + /* remove it from all sibling map's */ + clear_cpu_sibling_map(cpu); + + /* if this cpu is the last in the core group, remove all its info + * from mt_info structure + */ + if (last) + remove_from_mtinfo(cpu); +} + +extern void fixup_irqs(void); +/* must be called with cpucontrol mutex held */ +int __cpu_disable(void) +{ + int cpu = smp_processor_id(); + + /* + * dont permit boot processor for now + */ + if (cpu == 0) + return -EBUSY; + + remove_siblinginfo(cpu); + cpu_clear(cpu, cpu_online_map); + fixup_irqs(); + local_flush_tlb_all(); + cpu_clear(cpu, cpu_callin_map); + return 0; +} + +void __cpu_die(unsigned int cpu) +{ + unsigned int i; + + for (i = 0; i < 100; i++) { + /* They ack this in play_dead by setting CPU_DEAD */ + if (per_cpu(cpu_state, cpu) == CPU_DEAD) + { + printk ("CPU %d is now offline\n", cpu); + return; + } + msleep(100); + } + printk(KERN_ERR "CPU %u didn't die...\n", cpu); +} +#else /* !CONFIG_HOTPLUG_CPU */ +int __cpu_disable(void) +{ + return -ENOSYS; +} + +void __cpu_die(unsigned int cpu) +{ + /* We said "no" in __cpu_disable */ + BUG(); +} +#endif /* CONFIG_HOTPLUG_CPU */ + +void +smp_cpus_done (unsigned int dummy) +{ + int cpu; + unsigned long bogosum = 0; + + /* + * Allow the user to impress friends. + */ + + for (cpu = 0; cpu < NR_CPUS; cpu++) + if (cpu_online(cpu)) + bogosum += cpu_data(cpu)->loops_per_jiffy; + + printk(KERN_INFO "Total of %d processors activated (%lu.%02lu BogoMIPS).\n", + (int)num_online_cpus(), bogosum/(500000/HZ), (bogosum/(5000/HZ))%100); +} + +static inline void __devinit +set_cpu_sibling_map(int cpu) +{ + int i; + + for_each_online_cpu(i) { + if ((cpu_data(cpu)->socket_id == cpu_data(i)->socket_id)) { + cpu_set(i, cpu_core_map[cpu]); + cpu_set(cpu, cpu_core_map[i]); + if (cpu_data(cpu)->core_id == cpu_data(i)->core_id) { + cpu_set(i, cpu_sibling_map[cpu]); + cpu_set(cpu, cpu_sibling_map[i]); + } + } + } +} + +int __devinit +__cpu_up (unsigned int cpu) +{ + int ret; + int sapicid; + + sapicid = ia64_cpu_to_sapicid[cpu]; + if (sapicid == -1) + return -EINVAL; + + /* + * Already booted cpu? not valid anymore since we dont + * do idle loop tightspin anymore. + */ + if (cpu_isset(cpu, cpu_callin_map)) + return -EINVAL; + + per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; + /* Processor goes to start_secondary(), sets online flag */ + ret = do_boot_cpu(sapicid, cpu); + if (ret < 0) + return ret; + + if (cpu_data(cpu)->threads_per_core == 1 && + cpu_data(cpu)->cores_per_socket == 1) { + cpu_set(cpu, cpu_sibling_map[cpu]); + cpu_set(cpu, cpu_core_map[cpu]); + return 0; + } + + set_cpu_sibling_map(cpu); + + return 0; +} + +/* + * Assume that CPU's have been discovered by some platform-dependent interface. For + * SoftSDV/Lion, that would be ACPI. + * + * Setup of the IPI irq handler is done in irq.c:init_IRQ_SMP(). + */ +void __init +init_smp_config(void) +{ + struct fptr { + unsigned long fp; + unsigned long gp; + } *ap_startup; + long sal_ret; + + /* Tell SAL where to drop the AP's. */ + ap_startup = (struct fptr *) start_ap; + sal_ret = ia64_sal_set_vectors(SAL_VECTOR_OS_BOOT_RENDEZ, + ia64_tpa(ap_startup->fp), ia64_tpa(ap_startup->gp), 0, 0, 0, 0); + if (sal_ret < 0) + printk(KERN_ERR "SMP: Can't set SAL AP Boot Rendezvous: %s\n", + ia64_sal_strerror(sal_ret)); +} + +static inline int __devinit +check_for_mtinfo_index(void) +{ + int i; + + for_each_cpu(i) + if (!mt_info[i].valid) + return i; + + return -1; +} + +/* + * Search the mt_info to find out if this socket's cid/tid information is + * cached or not. If the socket exists, fill in the core_id and thread_id + * in cpuinfo + */ +static int __devinit +check_for_new_socket(__u16 logical_address, struct cpuinfo_ia64 *c) +{ + int i; + __u32 sid = c->socket_id; + + for_each_cpu(i) { + if (mt_info[i].valid && mt_info[i].proc_fixed_addr == logical_address + && mt_info[i].socket_id == sid) { + c->core_id = mt_info[i].core_id; + c->thread_id = mt_info[i].thread_id; + return 1; /* not a new socket */ + } + } + return 0; +} + +/* + * identify_siblings(cpu) gets called from identify_cpu. This populates the + * information related to logical execution units in per_cpu_data structure. + */ +void __devinit +identify_siblings(struct cpuinfo_ia64 *c) +{ + s64 status; + u16 pltid; + u64 proc_fixed_addr; + int count, i; + pal_logical_to_physical_t info; + + if (smp_num_cpucores == 1 && smp_num_siblings == 1) + return; + + if ((status = ia64_pal_logical_to_phys(0, &info)) != PAL_STATUS_SUCCESS) { + printk(KERN_ERR "ia64_pal_logical_to_phys failed with %ld\n", + status); + return; + } + if ((status = ia64_sal_physical_id_info(&pltid)) != PAL_STATUS_SUCCESS) { + printk(KERN_ERR "ia64_sal_pltid failed with %ld\n", status); + return; + } + if ((status = ia64_pal_fixed_addr(&proc_fixed_addr)) != PAL_STATUS_SUCCESS) { + printk(KERN_ERR "ia64_pal_fixed_addr failed with %ld\n", status); + return; + } + + c->socket_id = (pltid << 8) | info.overview_ppid; + c->cores_per_socket = info.overview_cpp; + c->threads_per_core = info.overview_tpc; + count = c->num_log = info.overview_num_log; + + /* If the thread and core id information is already cached, then + * we will simply update cpu_info and return. Otherwise, we will + * do the PAL calls and cache core and thread id's of all the siblings. + */ + if (check_for_new_socket(proc_fixed_addr, c)) + return; + + for (i = 0; i < count; i++) { + int index; + + if (i && (status = ia64_pal_logical_to_phys(i, &info)) + != PAL_STATUS_SUCCESS) { + printk(KERN_ERR "ia64_pal_logical_to_phys failed" + " with %ld\n", status); + return; + } + if (info.log2_la == proc_fixed_addr) { + c->core_id = info.log1_cid; + c->thread_id = info.log1_tid; + } + + index = check_for_mtinfo_index(); + /* We will not do the mt_info caching optimization in this case. + */ + if (index < 0) + continue; + + mt_info[index].valid = 1; + mt_info[index].socket_id = c->socket_id; + mt_info[index].core_id = info.log1_cid; + mt_info[index].thread_id = info.log1_tid; + mt_info[index].proc_fixed_addr = info.log2_la; + } +} +#endif /* CONFIG_SMP ifdef XEN */ diff --git a/xen/arch/ia64/process.c b/xen/arch/ia64/process.c index 7ee9914b83..5e80ab041b 100644 --- a/xen/arch/ia64/process.c +++ b/xen/arch/ia64/process.c @@ -224,7 +224,7 @@ panic_domain(regs,"psr.ic off, delivering fault=%lx,ipsr=%p,iip=%p,ifa=%p,isr=%p regs->cr_iip = ((unsigned long) PSCBX(v,iva) + vector) & ~0xffUL; regs->cr_ipsr = (regs->cr_ipsr & ~DELIVER_PSR_CLR) | DELIVER_PSR_SET; #ifdef CONFIG_SMP -#error "sharedinfo doesn't handle smp yet" +#warning "SMP FIXME: sharedinfo doesn't handle smp yet, need page per vcpu" #endif regs->r31 = &(((mapped_regs_t *)SHARED_ARCHINFO_ADDR)->ipsr); diff --git a/xen/arch/ia64/smp.c b/xen/arch/ia64/smp.c deleted file mode 100644 index ae581f3f56..0000000000 --- a/xen/arch/ia64/smp.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Intel SMP support routines. - * - * (c) 1995 Alan Cox, Building #3 - * (c) 1998-99, 2000 Ingo Molnar - * - * This code is released under the GNU General Public License version 2 or - * later. - */ - -//#include -#include -#include -#include -#include -//#include -#include -//#include -#include - - -//Huh? This seems to be used on ia64 even if !CONFIG_SMP -void flush_tlb_mask(cpumask_t mask) -{ - dummy(); -} -//#if CONFIG_SMP || IA64 -#if CONFIG_SMP -//Huh? This seems to be used on ia64 even if !CONFIG_SMP -void smp_send_event_check_mask(cpumask_t mask) -{ - dummy(); - //send_IPI_mask(cpu_mask, EVENT_CHECK_VECTOR); -} - - -//Huh? This seems to be used on ia64 even if !CONFIG_SMP -int try_flush_tlb_mask(cpumask_t mask) -{ - dummy(); - return 1; -} -#endif diff --git a/xen/arch/ia64/smpboot.c b/xen/arch/ia64/smpboot.c deleted file mode 100644 index 482349121b..0000000000 --- a/xen/arch/ia64/smpboot.c +++ /dev/null @@ -1,2 +0,0 @@ -// expand later -int ht_per_core = 1; diff --git a/xen/arch/ia64/xensetup.c b/xen/arch/ia64/xensetup.c index e7587522b6..bef39ead8e 100644 --- a/xen/arch/ia64/xensetup.c +++ b/xen/arch/ia64/xensetup.c @@ -27,6 +27,8 @@ char saved_command_line[COMMAND_LINE_SIZE]; struct vcpu *idle_task[NR_CPUS] = { &idle0_vcpu }; +cpumask_t cpu_present_map; + #ifdef CLONE_DOMAIN0 struct domain *clones[CLONE_DOMAIN0]; #endif diff --git a/xen/arch/ia64/xentime.c b/xen/arch/ia64/xentime.c index 843b9f3315..9447b9871a 100644 --- a/xen/arch/ia64/xentime.c +++ b/xen/arch/ia64/xentime.c @@ -32,6 +32,10 @@ #endif #include +#ifdef XEN +seqlock_t xtime_lock __cacheline_aligned_in_smp = SEQLOCK_UNLOCKED; +#endif + #define TIME_KEEPER_ID 0 extern unsigned long wall_jiffies; diff --git a/xen/include/asm-ia64/config.h b/xen/include/asm-ia64/config.h index a59e62e947..3cc3c96750 100644 --- a/xen/include/asm-ia64/config.h +++ b/xen/include/asm-ia64/config.h @@ -21,6 +21,22 @@ #define CONFIG_EFI_PCDP #define CONFIG_SERIAL_SGI_L1_CONSOLE +#undef CONFIG_XEN_SMP + +#ifdef CONFIG_XEN_SMP +#define CONFIG_SMP 1 +#define NR_CPUS 2 +#define CONFIG_NR_CPUS 2 +#else +#undef CONFIG_SMP +#define NR_CPUS 1 +#define CONFIG_NR_CPUS 1 +#endif +//#define NR_CPUS 16 +//#define CONFIG_NR_CPUS 16 +//leave SMP for a later time +//#undef CONFIG_SMP + #ifndef __ASSEMBLY__ // can't find where this typedef was before?!? @@ -75,13 +91,16 @@ extern char _end[]; /* standard ELF symbol */ //#define __cond_lock(x) (x) #define __must_check #define __deprecated +#ifndef RELOC_HIDE +# define RELOC_HIDE(ptr, off) \ + ({ unsigned long __ptr; \ + __ptr = (unsigned long) (ptr); \ + (typeof(ptr)) (__ptr + (off)); }) +#endif // xen/include/asm/config.h #define HZ 100 -// leave SMP for a later time -#define NR_CPUS 1 -//#define NR_CPUS 16 -//#define CONFIG_NR_CPUS 16 +// FIXME SMP: leave SMP for a later time #define barrier() __asm__ __volatile__("": : :"memory") /////////////////////////////////////////////////////////////// @@ -99,13 +118,18 @@ extern char _end[]; /* standard ELF symbol */ // from include/asm-ia64/smp.h #ifdef CONFIG_SMP -#error "Lots of things to fix to enable CONFIG_SMP!" +#warning "Lots of things to fix to enable CONFIG_SMP!" #endif +// FIXME SMP #define get_cpu() 0 #define put_cpu() do {} while(0) // needed for common/dom0_ops.c until hyperthreading is supported +#ifdef CONFIG_SMP +extern int smp_num_siblings; +#else #define smp_num_siblings 1 +#endif // from linux/include/linux/mm.h struct page; @@ -253,10 +277,6 @@ extern int ht_per_core; #define CONFIG_MCKINLEY -//#define CONFIG_SMP 1 -//#define CONFIG_NR_CPUS 2 -//leave SMP for a later time -#undef CONFIG_SMP #undef CONFIG_X86_LOCAL_APIC #undef CONFIG_X86_IO_APIC #undef CONFIG_X86_L1_CACHE_SHIFT diff --git a/xen/include/asm-ia64/linux-xen/asm/pal.h b/xen/include/asm-ia64/linux-xen/asm/pal.h index ebebcf584b..50508ff4f8 100644 --- a/xen/include/asm-ia64/linux-xen/asm/pal.h +++ b/xen/include/asm-ia64/linux-xen/asm/pal.h @@ -67,6 +67,7 @@ #define PAL_REGISTER_INFO 39 /* return AR and CR register information*/ #define PAL_SHUTDOWN 40 /* enter processor shutdown state */ #define PAL_PREFETCH_VISIBILITY 41 /* Make Processor Prefetches Visible */ +#define PAL_LOGICAL_TO_PHYSICAL 42 /* returns information on logical to physical processor mapping */ #define PAL_COPY_PAL 256 /* relocate PAL procedures and PAL PMI */ #define PAL_HALT_INFO 257 /* return the low power capabilities of processor */ @@ -1559,7 +1560,76 @@ ia64_pal_prefetch_visibility (s64 trans_type) return iprv.status; } +/* data structure for getting information on logical to physical mappings */ +typedef union pal_log_overview_u { + struct { + u64 num_log :16, /* Total number of logical + * processors on this die + */ + tpc :8, /* Threads per core */ + reserved3 :8, /* Reserved */ + cpp :8, /* Cores per processor */ + reserved2 :8, /* Reserved */ + ppid :8, /* Physical processor ID */ + reserved1 :8; /* Reserved */ + } overview_bits; + u64 overview_data; +} pal_log_overview_t; + +typedef union pal_proc_n_log_info1_u{ + struct { + u64 tid :16, /* Thread id */ + reserved2 :16, /* Reserved */ + cid :16, /* Core id */ + reserved1 :16; /* Reserved */ + } ppli1_bits; + u64 ppli1_data; +} pal_proc_n_log_info1_t; + +typedef union pal_proc_n_log_info2_u { + struct { + u64 la :16, /* Logical address */ + reserved :48; /* Reserved */ + } ppli2_bits; + u64 ppli2_data; +} pal_proc_n_log_info2_t; + +typedef struct pal_logical_to_physical_s +{ + pal_log_overview_t overview; + pal_proc_n_log_info1_t ppli1; + pal_proc_n_log_info2_t ppli2; +} pal_logical_to_physical_t; + +#define overview_num_log overview.overview_bits.num_log +#define overview_tpc overview.overview_bits.tpc +#define overview_cpp overview.overview_bits.cpp +#define overview_ppid overview.overview_bits.ppid +#define log1_tid ppli1.ppli1_bits.tid +#define log1_cid ppli1.ppli1_bits.cid +#define log2_la ppli2.ppli2_bits.la + +/* Get information on logical to physical processor mappings. */ +static inline s64 +ia64_pal_logical_to_phys(u64 proc_number, pal_logical_to_physical_t *mapping) +{ + struct ia64_pal_retval iprv; + + PAL_CALL(iprv, PAL_LOGICAL_TO_PHYSICAL, proc_number, 0, 0); + + if (iprv.status == PAL_STATUS_SUCCESS) + { + if (proc_number == 0) + mapping->overview.overview_data = iprv.v0; + mapping->ppli1.ppli1_data = iprv.v1; + mapping->ppli2.ppli2_data = iprv.v2; + } + + return iprv.status; +} +#ifdef XEN #include +#endif #endif /* __ASSEMBLY__ */ #endif /* _ASM_IA64_PAL_H */ diff --git a/xen/include/asm-ia64/linux-xen/asm/processor.h b/xen/include/asm-ia64/linux-xen/asm/processor.h index 8ef0726365..a35d69a9a8 100644 --- a/xen/include/asm-ia64/linux-xen/asm/processor.h +++ b/xen/include/asm-ia64/linux-xen/asm/processor.h @@ -164,6 +164,13 @@ struct cpuinfo_ia64 { #ifdef CONFIG_SMP __u64 loops_per_jiffy; int cpu; + __u32 socket_id; /* physical processor socket id */ + __u16 core_id; /* core id */ + __u16 thread_id; /* thread id */ + __u16 num_log; /* Total number of logical processors on + * this socket that were successfully booted */ + __u8 cores_per_socket; /* Cores per processor socket */ + __u8 threads_per_core; /* Threads per core */ #endif /* CPUID-derived information: */ diff --git a/xen/include/asm-ia64/linux/asm/spinlock.h b/xen/include/asm-ia64/linux-xen/asm/spinlock.h similarity index 83% rename from xen/include/asm-ia64/linux/asm/spinlock.h rename to xen/include/asm-ia64/linux-xen/asm/spinlock.h index 909936f255..6082158255 100644 --- a/xen/include/asm-ia64/linux/asm/spinlock.h +++ b/xen/include/asm-ia64/linux-xen/asm/spinlock.h @@ -22,6 +22,10 @@ typedef struct { #ifdef CONFIG_PREEMPT unsigned int break_lock; #endif +#ifdef XEN + unsigned char recurse_cpu; + unsigned char recurse_cnt; +#endif } spinlock_t; #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } @@ -116,6 +120,35 @@ do { \ #define _raw_spin_trylock(x) (cmpxchg_acq(&(x)->lock, 0, 1) == 0) #define spin_unlock_wait(x) do { barrier(); } while ((x)->lock) +#ifdef XEN +/* + * spin_[un]lock_recursive(): Use these forms when the lock can (safely!) be + * reentered recursively on the same CPU. All critical regions that may form + * part of a recursively-nested set must be protected by these forms. If there + * are any critical regions that cannot form part of such a set, they can use + * standard spin_[un]lock(). + */ +#define _raw_spin_lock_recursive(_lock) \ + do { \ + int cpu = smp_processor_id(); \ + if ( likely((_lock)->recurse_cpu != cpu) ) \ + { \ + spin_lock(_lock); \ + (_lock)->recurse_cpu = cpu; \ + } \ + (_lock)->recurse_cnt++; \ + } while ( 0 ) + +#define _raw_spin_unlock_recursive(_lock) \ + do { \ + if ( likely(--(_lock)->recurse_cnt == 0) ) \ + { \ + (_lock)->recurse_cpu = -1; \ + spin_unlock(_lock); \ + } \ + } while ( 0 ) +#endif + typedef struct { volatile unsigned int read_counter : 31; volatile unsigned int write_lock : 1; diff --git a/xen/include/asm-ia64/linux-xen/asm/system.h b/xen/include/asm-ia64/linux-xen/asm/system.h index 17f1acc4f4..d8d9dd20db 100644 --- a/xen/include/asm-ia64/linux-xen/asm/system.h +++ b/xen/include/asm-ia64/linux-xen/asm/system.h @@ -247,9 +247,9 @@ extern void ia64_load_extra (struct task_struct *task); */ # define switch_to(prev,next,last) do { \ if (ia64_psr(ia64_task_regs(prev))->mfh && ia64_is_local_fpu_owner(prev)) { \ - ia64_psr(ia64_task_regs(prev))->mfh = 0; \ - (prev)->thread.flags |= IA64_THREAD_FPH_VALID; \ - __ia64_save_fpu((prev)->thread.fph); \ + /* ia64_psr(ia64_task_regs(prev))->mfh = 0; */ \ + /* (prev)->thread.flags |= IA64_THREAD_FPH_VALID; */ \ + /* __ia64_save_fpu((prev)->thread.fph); */ \ } \ __switch_to(prev, next, last); \ } while (0) diff --git a/xen/include/asm-ia64/linux-xen/asm/tlbflush.h b/xen/include/asm-ia64/linux-xen/asm/tlbflush.h new file mode 100644 index 0000000000..3cab2a5af2 --- /dev/null +++ b/xen/include/asm-ia64/linux-xen/asm/tlbflush.h @@ -0,0 +1,105 @@ +#ifndef _ASM_IA64_TLBFLUSH_H +#define _ASM_IA64_TLBFLUSH_H + +/* + * Copyright (C) 2002 Hewlett-Packard Co + * David Mosberger-Tang + */ + +#include + +#include + +#include +#include +#include + +/* + * Now for some TLB flushing routines. This is the kind of stuff that + * can be very expensive, so try to avoid them whenever possible. + */ + +/* + * Flush everything (kernel mapping may also have changed due to + * vmalloc/vfree). + */ +extern void local_flush_tlb_all (void); + +#ifdef CONFIG_SMP + extern void smp_flush_tlb_all (void); + extern void smp_flush_tlb_mm (struct mm_struct *mm); +# define flush_tlb_all() smp_flush_tlb_all() +#else +# define flush_tlb_all() local_flush_tlb_all() +#endif + +static inline void +local_finish_flush_tlb_mm (struct mm_struct *mm) +{ +#ifndef XEN + if (mm == current->active_mm) + activate_context(mm); +#endif +} + +/* + * Flush a specified user mapping. This is called, e.g., as a result of fork() and + * exit(). fork() ends up here because the copy-on-write mechanism needs to write-protect + * the PTEs of the parent task. + */ +static inline void +flush_tlb_mm (struct mm_struct *mm) +{ + if (!mm) + return; + +#ifndef XEN + mm->context = 0; +#endif + + if (atomic_read(&mm->mm_users) == 0) + return; /* happens as a result of exit_mmap() */ + +#ifdef CONFIG_SMP + smp_flush_tlb_mm(mm); +#else + local_finish_flush_tlb_mm(mm); +#endif +} + +extern void flush_tlb_range (struct vm_area_struct *vma, unsigned long start, unsigned long end); + +/* + * Page-granular tlb flush. + */ +static inline void +flush_tlb_page (struct vm_area_struct *vma, unsigned long addr) +{ +#ifdef CONFIG_SMP + flush_tlb_range(vma, (addr & PAGE_MASK), (addr & PAGE_MASK) + PAGE_SIZE); +#else + if (vma->vm_mm == current->active_mm) + ia64_ptcl(addr, (PAGE_SHIFT << 2)); +#ifndef XEN + else + vma->vm_mm->context = 0; +#endif +#endif +} + +/* + * Flush the TLB entries mapping the virtually mapped linear page + * table corresponding to address range [START-END). + */ +static inline void +flush_tlb_pgtables (struct mm_struct *mm, unsigned long start, unsigned long end) +{ + /* + * Deprecated. The virtual page table is now flushed via the normal gather/flush + * interface (see tlb.h). + */ +} + +#define flush_tlb_kernel_range(start, end) flush_tlb_all() /* XXX fix me */ + +#endif /* _ASM_IA64_TLBFLUSH_H */ diff --git a/xen/include/asm-ia64/linux/asm/sal.h b/xen/include/asm-ia64/linux/asm/sal.h index ea1ed377de..29df88bdd2 100644 --- a/xen/include/asm-ia64/linux/asm/sal.h +++ b/xen/include/asm-ia64/linux/asm/sal.h @@ -91,6 +91,7 @@ extern spinlock_t sal_lock; #define SAL_PCI_CONFIG_READ 0x01000010 #define SAL_PCI_CONFIG_WRITE 0x01000011 #define SAL_FREQ_BASE 0x01000012 +#define SAL_PHYSICAL_ID_INFO 0x01000013 #define SAL_UPDATE_PAL 0x01000020 @@ -815,6 +816,17 @@ ia64_sal_update_pal (u64 param_buf, u64 scratch_buf, u64 scratch_buf_size, return isrv.status; } +/* Get physical processor die mapping in the platform. */ +static inline s64 +ia64_sal_physical_id_info(u16 *splid) +{ + struct ia64_sal_retval isrv; + SAL_CALL(isrv, SAL_PHYSICAL_ID_INFO, 0, 0, 0, 0, 0, 0, 0); + if (splid) + *splid = isrv.v0; + return isrv.status; +} + extern unsigned long sal_platform_features; extern int (*salinfo_platform_oemdata)(const u8 *, u8 **, u64 *); @@ -832,6 +844,44 @@ extern int ia64_sal_oemcall_nolock(struct ia64_sal_retval *, u64, u64, u64, u64, u64, u64, u64, u64); extern int ia64_sal_oemcall_reentrant(struct ia64_sal_retval *, u64, u64, u64, u64, u64, u64, u64, u64); +#ifdef CONFIG_HOTPLUG_CPU +/* + * System Abstraction Layer Specification + * Section 3.2.5.1: OS_BOOT_RENDEZ to SAL return State. + * Note: region regs are stored first in head.S _start. Hence they must + * stay up front. + */ +struct sal_to_os_boot { + u64 rr[8]; /* Region Registers */ + u64 br[6]; /* br0: return addr into SAL boot rendez routine */ + u64 gr1; /* SAL:GP */ + u64 gr12; /* SAL:SP */ + u64 gr13; /* SAL: Task Pointer */ + u64 fpsr; + u64 pfs; + u64 rnat; + u64 unat; + u64 bspstore; + u64 dcr; /* Default Control Register */ + u64 iva; + u64 pta; + u64 itv; + u64 pmv; + u64 cmcv; + u64 lrr[2]; + u64 gr[4]; + u64 pr; /* Predicate registers */ + u64 lc; /* Loop Count */ + struct ia64_fpreg fp[20]; +}; + +/* + * Global array allocated for NR_CPUS at boot time + */ +extern struct sal_to_os_boot sal_boot_rendez_state[NR_CPUS]; + +extern void ia64_jump_to_sal(struct sal_to_os_boot *); +#endif extern void ia64_sal_handler_init(void *entry_point, void *gpval); diff --git a/xen/include/asm-ia64/linux/asm/tlbflush.h b/xen/include/asm-ia64/linux/asm/tlbflush.h deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/xen/include/asm-ia64/linux/notifier.h b/xen/include/asm-ia64/linux/notifier.h new file mode 100644 index 0000000000..5937dd6053 --- /dev/null +++ b/xen/include/asm-ia64/linux/notifier.h @@ -0,0 +1,76 @@ +/* + * Routines to manage notifier chains for passing status changes to any + * interested routines. We need this instead of hard coded call lists so + * that modules can poke their nose into the innards. The network devices + * needed them so here they are for the rest of you. + * + * Alan Cox + */ + +#ifndef _LINUX_NOTIFIER_H +#define _LINUX_NOTIFIER_H +#include + +struct notifier_block +{ + int (*notifier_call)(struct notifier_block *self, unsigned long, void *); + struct notifier_block *next; + int priority; +}; + + +#ifdef __KERNEL__ + +extern int notifier_chain_register(struct notifier_block **list, struct notifier_block *n); +extern int notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n); +extern int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v); + +#define NOTIFY_DONE 0x0000 /* Don't care */ +#define NOTIFY_OK 0x0001 /* Suits me */ +#define NOTIFY_STOP_MASK 0x8000 /* Don't call further */ +#define NOTIFY_BAD (NOTIFY_STOP_MASK|0x0002) /* Bad/Veto action */ +/* + * Clean way to return from the notifier and stop further calls. + */ +#define NOTIFY_STOP (NOTIFY_OK|NOTIFY_STOP_MASK) + +/* + * Declared notifiers so far. I can imagine quite a few more chains + * over time (eg laptop power reset chains, reboot chain (to clean + * device units up), device [un]mount chain, module load/unload chain, + * low memory chain, screenblank chain (for plug in modular screenblankers) + * VC switch chains (for loadable kernel svgalib VC switch helpers) etc... + */ + +/* netdevice notifier chain */ +#define NETDEV_UP 0x0001 /* For now you can't veto a device up/down */ +#define NETDEV_DOWN 0x0002 +#define NETDEV_REBOOT 0x0003 /* Tell a protocol stack a network interface + detected a hardware crash and restarted + - we can use this eg to kick tcp sessions + once done */ +#define NETDEV_CHANGE 0x0004 /* Notify device state change */ +#define NETDEV_REGISTER 0x0005 +#define NETDEV_UNREGISTER 0x0006 +#define NETDEV_CHANGEMTU 0x0007 +#define NETDEV_CHANGEADDR 0x0008 +#define NETDEV_GOING_DOWN 0x0009 +#define NETDEV_CHANGENAME 0x000A +#define NETDEV_FEAT_CHANGE 0x000B + +#define SYS_DOWN 0x0001 /* Notify of system down */ +#define SYS_RESTART SYS_DOWN +#define SYS_HALT 0x0002 /* Notify of system halt */ +#define SYS_POWER_OFF 0x0003 /* Notify of system power off */ + +#define NETLINK_URELEASE 0x0001 /* Unicast netlink socket released */ + +#define CPU_ONLINE 0x0002 /* CPU (unsigned)v is up */ +#define CPU_UP_PREPARE 0x0003 /* CPU (unsigned)v coming up */ +#define CPU_UP_CANCELED 0x0004 /* CPU (unsigned)v NOT coming up */ +#define CPU_DOWN_PREPARE 0x0005 /* CPU (unsigned)v going down */ +#define CPU_DOWN_FAILED 0x0006 /* CPU (unsigned)v NOT going down */ +#define CPU_DEAD 0x0007 /* CPU (unsigned)v dead */ + +#endif /* __KERNEL__ */ +#endif /* _LINUX_NOTIFIER_H */ diff --git a/xen/include/asm-ia64/vhpt.h b/xen/include/asm-ia64/vhpt.h index 2ef29b32af..8402d878b4 100644 --- a/xen/include/asm-ia64/vhpt.h +++ b/xen/include/asm-ia64/vhpt.h @@ -129,7 +129,7 @@ struct vhpt_lf_entry { #define VHPT_CCHAIN_LOOKUP(Name, i_or_d) #else #ifdef CONFIG_SMP -#error "VHPT_CCHAIN_LOOKUP needs a semaphore on the VHPT!" +#warning "FIXME SMP: VHPT_CCHAIN_LOOKUP needs a semaphore on the VHPT!" #endif // VHPT_CCHAIN_LOOKUP is intended to run with psr.i+ic off -- 2.30.2